package com.hmall.trade.service.impl;

import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.cart.CartClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.api.item.ItemClient;
import com.hmall.common.constants.MqConstants;
import com.hmall.common.exception.BadRequestException;
import com.hmall.common.utils.UserContext;
import com.hmall.trade.domain.dto.OrderFormDTO;
import com.hmall.trade.domain.po.Order;
import com.hmall.trade.domain.po.OrderDetail;
import com.hmall.trade.mapper.OrderDetailMapper;
import com.hmall.trade.mapper.OrderMapper;
import com.hmall.trade.service.IOrderDetailService;
import com.hmall.trade.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final ItemClient itemClient;

    private final IOrderDetailService detailService;

    private final CartClient cartClient;

    private final RabbitTemplate rabbitTemplate;
    private final OrderDetailMapper orderDetailMapper;

    @Override
    @GlobalTransactional
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.订单数据
        Order order = new Order();
        // 1.1.查询商品
        List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
        // 1.2.获取商品id和数量的Map
        Map<Long, Integer> itemNumMap = detailDTOS.stream()
                .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
        Set<Long> itemIds = itemNumMap.keySet();
        // 1.3.查询商品
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
        if (items == null || items.size() < itemIds.size()) {
            throw new BadRequestException("商品不存在");
        }
        // 1.4.基于商品价格、购买数量计算商品总价：totalFee
        int total = 0;
        for (ItemDTO item : items) {
            total += item.getPrice();
            itemNumMap.get(item.getId());
        }
        order.setTotalFee(total);
        // 1.5.其它属性
        order.setPaymentType(orderFormDTO.getPaymentType());
        order.setUserId(UserContext.getUser());
        order.setStatus(1);
        // 1.6.将Order写入数据库order表中
        save(order);

        // 2.保存订单详情
        List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
        detailService.saveBatch(details);

        // 3.扣减库存
        try {
            itemClient.deductStock(detailDTOS);
        } catch (Exception e) {
            throw new RuntimeException("库存不足！");
        }

        // 4.清理购物车商品
        cartClient.deleteCartItemByIds(order.getId(), itemIds);

        // 5.发送延迟消息
        log.info("[开始]发送延迟消息时间：{}", LocalDateTime.now());
        String stringOrderId = order.getId().toString();
        Message message = MessageBuilder.withBody(stringOrderId.getBytes(StandardCharsets.UTF_8))
                //消息延迟投递到队列的时间，单位毫秒
                .setHeader("x-delay", "10000")
                //普通字符串必须指定为文本
                .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
                .build();
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(UuidUtils.generateUuid().toString());
        rabbitTemplate.convertAndSend(MqConstants.DELAY_EXCHANGE_NAME, MqConstants.DELAY_ORDER_KEY, message, correlationData);
        log.info("[结束]发送延迟消息时间：{}", LocalDateTime.now());

        return order.getId();
    }

    private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
        List<OrderDetail> details = new ArrayList<>(items.size());
        for (ItemDTO item : items) {
            OrderDetail detail = new OrderDetail();
            detail.setName(item.getName());
            detail.setSpec(item.getSpec());
            detail.setPrice(item.getPrice());
            detail.setNum(numMap.get(item.getId()));
            detail.setItemId(item.getId());
            detail.setImage(item.getImage());
            detail.setOrderId(orderId);
            details.add(detail);
        }
        return details;
    }

    @Override
    public void markOrderPaySuccess(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(2);
        order.setPayTime(LocalDateTime.now());
        updateById(order);
    }

    /**
     * 此方法为取消订单的service方法
     *
     * @param orderId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelOrder(Long orderId) {
        if (orderId == null) {
            throw new RuntimeException("取消订单Id为空！");
        }
        Order orderUnPay = this.lambdaQuery().eq(Order::getId, orderId).eq(Order::getStatus, 1).one();
        if (orderUnPay == null) {
            throw new RuntimeException("暂时未查到未支付订单！");
        }

        // 校验订单超时时间 模拟订单创建时间：2025-06-23 19:30:00
        LocalDateTime orderCreateTime = orderUnPay.getCreateTime();
        // 超时时间为30分钟 创建时间 + 30分钟 → 2025-06-23 20:00:00
        LocalDateTime expirationTime = orderCreateTime.plusMinutes(30);
        // 系统当前时间 模拟当前时间：2025-06-23 20:05:00
        LocalDateTime now = LocalDateTime.now();
        if (now.isAfter(expirationTime)) {
            // 取消订单
            log.info("订单已超时，无法继续处理！将订单时间调整为取消");
            boolean updateOrderStates = this.lambdaUpdate()
                    .set(Order::getStatus, 5)
                    .eq(Order::getId, orderId).update();
            if (!updateOrderStates) {
                throw new RuntimeException("取消订单状态失败！");
            }

            // 查询订单详情来回滚库存数
            List<OrderDetailDTO> detailDTOs = new ArrayList<>();

            // 恢复库存
            List<OrderDetail> orderDetailList = detailService.lambdaQuery().eq(OrderDetail::getOrderId, orderId).list();
            for (OrderDetail orderDetail : orderDetailList) {
                OrderDetailDTO orderDetailDTO = new OrderDetailDTO();
                orderDetailDTO.setNum(-orderDetail.getNum());
                orderDetailDTO.setItemId(orderDetail.getItemId());
                detailDTOs.add(orderDetailDTO);
            }
            itemClient.deductStock(detailDTOs);
            log.info("恢复库存成功！！！");
        }
    }
}